 
  

 






<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do;jsessionid=4FCCB481C702D708A7360133D128E359?Id=184 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:27:29 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
<head>
 <title>
  Java Practices -> Simplify database operations
 </title>
 <link rel="stylesheet" type="text/css" href="../stylesheet8.css" media="all">
 
 <link rel="shortcut icon" href='../images/favicon.ico' type="image/vnd.microsoft.icon">
 <meta name="description" content="Concise presentations of java programming practices, tasks, and conventions, amply illustrated with syntax highlighted code examples.">
 
 <meta name='keywords' content='ModelFromParams,MyMessageDAOSql,ResultSet,SELECT,SqlFetcher,database,java,java programming,java practices,java idiom,java style,java design patterns,java coding conventions,'>
 
 
</head>
 
<body>


<div class='menu-bar'>
 
  <a href='../home/HomeAction.html' title='Table of Contents'>Home</a> |
  <a href='../vote/VoteSummaryAction-2.html' title='View Poll Results'>Poll</a> |
   
  <A href='../feedback/FeedbackAction451f-2.html?Operation=Show' title='Send Your Feedback'>Wiki</a> |
  <b><a href='../source/SourceAction-2.html' title='Grab Source Code'>Source Code</a></b><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |

  <a href='http://www.web4j.com/Java_Web_Application_Framework_Overview.jsp?From=1' title='Free Download - Java Web Application Framework'><b>WEB4J</b></a> |
  
  <a href='http://www.date4j.net/' title='Replacement for java.util.Date'><b>DATE4J</b></a> |

   <a href='../references/ReferencesAction-2.html' title='References'>Links</a>
   
  <form action='http://www.javapractices.com/search/SearchAction.do' method='get' class='search-form'>
   <input type='text' name='SearchTerms' value="" size=12 maxlength=50 class='search'>
   <input type='submit' value="Search">
  </form>
 
</div>

<P>



  

 






<p class="display-messages">

 

 

</p>


<div class="main-layout">
 
   

 




<div class='page-title'>Simplify database operations</div>

<div class='main-body'>
 
<br>
Since fetch and edit operations are such common tasks in many applications, it's beneficial if  
these tasks can be made as simple and compact as possible. 
Even when using tools on top of JDBC, there are very often ways of simplifying code and removing repetition.

<P>If you find that your data access code is becoming repetitive, look for ways to remove the 
repetition - utility classes, <a href='TopicActione01b-2.html'>template methods</a>, and so on.

<P><b>Example</b>

<P>Here is a DAO taken from the <a href="TopicAction5f31-2.html">WEB4J</a> example application. 
This example is already quite compact. The methods are short, and read at a high level.
If you look closely, however, you can see that one item is still repeated.
Can you spot it? (See answer below.)
<br>
<PRE>

<span class='keyword'>package</span> hirondelle.fish.main.member;

<span class='keyword'>import</span> <span class='keyword'>static</span> hirondelle.fish.main.member.MemberAction.COUNT_ACTIVE_MEMBERS;
<span class='keyword'>import</span> <span class='keyword'>static</span> hirondelle.fish.main.member.MemberAction.MEMBER_ADD;
<span class='keyword'>import</span> <span class='keyword'>static</span> hirondelle.fish.main.member.MemberAction.MEMBER_CHANGE;
<span class='keyword'>import</span> <span class='keyword'>static</span> hirondelle.fish.main.member.MemberAction.MEMBER_DELETE;
<span class='keyword'>import</span> <span class='keyword'>static</span> hirondelle.fish.main.member.MemberAction.MEMBER_FETCH;
<span class='keyword'>import</span> <span class='keyword'>static</span> hirondelle.fish.main.member.MemberAction.MEMBER_LIST;
<span class='keyword'>import</span> hirondelle.fish.test.doubles.FakeDAOBehavior;
<span class='keyword'>import</span> hirondelle.web4j.database.DAOException;
<span class='keyword'>import</span> hirondelle.web4j.database.Db;
<span class='keyword'>import</span> hirondelle.web4j.database.DuplicateException;
<span class='keyword'>import</span> hirondelle.web4j.database.ForeignKeyException;
<span class='keyword'>import</span> hirondelle.web4j.model.Id;
<span class='keyword'>import</span> hirondelle.web4j.util.Util;

<span class='keyword'>import</span> java.util.Collection;
<span class='keyword'>import</span> java.util.List;
<span class='keyword'>import</span> java.util.logging.Logger;

<span class='comment'>/** 
 Data Access Object (DAO) for {@link Member} objects.
 
 &lt;P&gt;&lt;b&gt;Design Note&lt;/b&gt;&lt;br&gt; 
 &lt;P&gt;This class is not final. This allows creating {@link MemberDAOFake} as a subclass.
 Instead of using a subclass to define the fake DAO, some might prefer to define  
 an interface for the DAO instead, along with two concrete implementations, 
 one for the real DAO, and one for the fake DAO. 
 
 &lt;P&gt;The subclass style was used here since it seems a bit more compact : only 
 two top-level items need to be defined, not three.
 
 &lt;P&gt;Either style will work.
*/</span>
<span class='keyword'>public</span> <span class='keyword'>class</span> MemberDAO {

  <span class='comment'>/**
   Return either a real or a fake DAO.
   
   &lt;P&gt;The underlying mechanism for swapping between the two implementations 
   relies on a simple &lt;tt&gt;System&lt;/tt&gt; property.  
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> MemberDAO getInstance(){
    MemberDAO result = <span class='keyword'>null</span>;
    String environmentSetting = System.getProperty(FakeDAOBehavior.USE_FAKE_DAOS);
    <span class='keyword'>if</span>( Boolean.TRUE.toString().equalsIgnoreCase(environmentSetting) ) {
      fLogger.fine(<span class='literal'>"Using fake Member DAO."</span>);
      result = <span class='keyword'>new</span> MemberDAOFake();
    }
    <span class='keyword'>else</span> {
      fLogger.fine(<span class='literal'>"Using real Member DAO."</span> );
      result = <span class='keyword'>new</span> MemberDAO();
    }
    <span class='keyword'>return</span> result;
  }
  
  <span class='comment'>/**
   Return a &lt;tt&gt;List&lt;/tt&gt; of all {@link Member} objects, sorted by Member Name.
  */</span>
  List&lt;Member&gt; list() <span class='keyword'>throws</span> DAOException {
    <span class='keyword'>return</span> Db.list(Member.<span class='keyword'>class</span>, MEMBER_LIST);
  }
   
  <span class='comment'>/**
   Return a single {@link Member} identified by its id.
  */</span>
  <span class='keyword'>public</span> Member fetch(Id aMemberId) <span class='keyword'>throws</span> DAOException {
    <span class='keyword'>return</span> Db.fetch(Member.<span class='keyword'>class</span>, MEMBER_FETCH, aMemberId);
  }
   
  <span class='comment'>/**
   Add a new {@link Member} to the database.
   
   &lt;P&gt;The name of the &lt;tt&gt;Member&lt;/tt&gt; must be unique. If there is a name 
   conflict, then a {@link DuplicateException} is thrown.
   
   @return the autogenerated database id.
  */</span>
  Id add(Member aMember) <span class='keyword'>throws</span> DAOException, DuplicateException {
    <span class='keyword'>return</span> Db.add(MEMBER_ADD, baseParamsFrom(aMember));
  }
   
  <span class='comment'>/**
   Update an existing {@link Member}.
    
   &lt;P&gt;The name of the &lt;tt&gt;Member&lt;/tt&gt; must be unique. If there is a name 
   conflict, then a {@link DuplicateException} is thrown.
   
   @return &lt;tt&gt;true&lt;/tt&gt; only if a record is actually edited. 
  */</span>
  <span class='keyword'>boolean</span> change(Member aMember) <span class='keyword'>throws</span> DAOException, DuplicateException {
    Object[] params = Db.addIdTo(baseParamsFrom(aMember), aMember.getId());
    <span class='keyword'>return</span> Util.isSuccess(Db.edit(MEMBER_CHANGE, params));
  }
  
  <span class='comment'>/**
   Delete a single {@link Member}.
   
   &lt;P&gt;If an item is linked to this {@link Member}, then deletion will fail, and a 
   {@link DAOException} is thrown.
  */</span>
  <span class='keyword'>int</span> delete(Id aMemberId) <span class='keyword'>throws</span> DAOException {
     <span class='keyword'>return</span> Db.delete(MEMBER_DELETE, aMemberId);
  }
   
  <span class='comment'>/**
   Delete one or more {@link Member}s in one operation. 
   
   &lt;P&gt;Returns the total number of deleted items.
   
   &lt;P&gt;&lt;i&gt;This method has an unusual policy regarding failed operations.&lt;/i&gt; 
   Each delete operation is treated as a &lt;i&gt;separate&lt;/i&gt; item. 
   No transactions are used here. 
   If one delete operation fails (for example, because of a foreign key constraint), 
   then this method will not stop. Rather, it will keep trying to 
   delete items in sequence, until it gets to the end of the given Member ids.
   
   &lt;P&gt;It is important to be aware of this policy. You may implement in another style, if 
   desired.  It's highly recommended that the calling action examine the return value of 
   this method, and compare it with the number of Member Ids, to detect if an 
   error has occurred.
   
   &lt;P&gt;(An interesting alternative policy would be to return not a single integer, 
   but the list of Ids of items that were successfully (or unsuccessfully) deleted.)
  */</span>
  <span class='keyword'>int</span> deleteMany(Collection&lt;Id&gt; aMemberIds) <span class='keyword'>throws</span> DAOException {
    <span class='keyword'>int</span> result = <span class='literal'>0</span>;
    <span class='keyword'>for</span>(Id id: aMemberIds){
      <span class='keyword'>try</span> {
        result = result +  Db.delete(MEMBER_DELETE, id);
      }
      <span class='keyword'>catch</span>(ForeignKeyException ex){
        fLogger.fine(
          <span class='literal'>"Foreign key constraint violated. Cannot delete Member with id : "</span> + 
          id + <span class='literal'>" Root cause : "</span> + ex.getRootCause()
        );
      }
    }
    <span class='keyword'>return</span> result;
  }
  
  <span class='comment'>/** Return the number of currently active members.  */</span>
  Integer getNumActiveMembers() <span class='keyword'>throws</span> DAOException {
    <span class='keyword'>return</span> Db.fetchValue(Integer.<span class='keyword'>class</span>, COUNT_ACTIVE_MEMBERS);
  }
  
  <span class='comment'>// PRIVATE //
</span>  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> Logger fLogger = Util.getLogger(MemberDAO.<span class='keyword'>class</span>);
  
  <span class='comment'>/*
   Small defect: would like to declare a private constructor here, such that the 
   caller is forced to use the factory method. But that can't be done, since  
   the constructor needs to be visible from the 'fake' subclass.
  */</span>

  <span class='keyword'>private</span> Object[] baseParamsFrom(Member aMember){
    <span class='keyword'>return</span> <span class='keyword'>new</span> Object[]{
      aMember.getName(), aMember.getIsActive(), aMember.getDisposition().getId()
    };
  }
}
 
</PRE>
<br>
<br>The answer is that the <tt>list</tt> and <tt>fetch</tt> methods repeat the same piece of data - the 
class literal <tt>Member.class</tt>. Like any repeated literal, it should likely 
be placed in a <tt>private static final</tt> field. Since that would be a common occurence, 
it would likely be beneficial to make a habit of doing so, and of giving a conventional name to 
the field as well, such as <tt>MODEL</tt>.
<br>
<br>

</div>




<div class='topic-section'>See Also :</div>
<div class='main-body'>
 
  
  <a href='TopicAction0d22-2.html?Id=76'>Reduce database code duplication</a> <br>
 
  
  <a href='TopicActione914-2.html?Id=105'>Keep SQL out of code</a> <br>
 
  
  <a href='TopicAction1a25-2.html?Id=124'>Consider data layer tools</a> <br>
 
  
  <a href='TopicActionf9c8-2.html?Id=183'>Encapsulate connections</a> <br>
 
  
  <a href='TopicAction5f31-2.html?Id=188'>A Web App Framework - WEB4J</a> <br>
 
  
  <a href='TopicAction3b51-2.html?Id=189'>Use template for transactions</a> <br>
 
</div>


<div class='topic-section'>Would you use this technique?</div>
<div class='main-body'>
  
  <form action="http://www.javapractices.com/vote/AddVoteAction.do" method='post'>
    Yes<input type='radio' name='Choice' value='Y' >
    &nbsp;&nbsp;No<input type='radio' name='Choice' value='N'>
    &nbsp;&nbsp;Undecided<input type='radio' name='Choice' value="?" >
    &nbsp;&nbsp;<input type=submit value="Vote" >
    <input type='hidden' name='Operation' value='Apply'>
    <input type='hidden' name='TopicId' value='184'>
  </form>
</div>

<div style='height:10.0em;'></div>

 
 
</div>

  

 





<div align='center' class='legalese'>  
&copy; 2011 Hirondelle Systems |
<a href='../source/SourceAction-2.html'><b>Source Code</b></a><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |
<a href="mailto:webmaster@javapractices.com">Contact</a> |
<a href="http://creativecommons.org/licenses/by-nc-sa/1.0/">License</a> |
<a href='../apps/cjp.rss'>RSS</a>
<!-- ukey="2AC36CD2" -->
<!-- ckey="16DF3D87" -->
<br>

 Individual code snippets can be used under this <a href='../LICENSE.txt'>BSD license</a> - Last updated on June 6, 2010.<br>
 Over 150,000 unique IPs last month - <span title='Java Practices 2.6.5, Mon May 16 00:00:00 EDT 2011'>Built with</span> <a href='http://www.web4j.com/'>WEB4J</a>.<br>
 - In Memoriam : Bill Dirani -
</div>

<script src="../../www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-2633428-1";
urchinTracker();
</script>



</body>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do;jsessionid=4FCCB481C702D708A7360133D128E359?Id=184 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:27:29 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
</html>
